﻿using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Nop.Admin.Controllers;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Directory;
using Nop.Plugin.Pricing.PreciousMetals.Domain;
using Nop.Plugin.Pricing.PreciousMetals.Models;
using Nop.Plugin.Pricing.PreciousMetals.Services;
using Nop.Services.Catalog;
using Nop.Services.Directory;
using Nop.Services.Security;
using Nop.Web.Framework.Controllers;
using Telerik.Web.Mvc;
using System.Threading;

namespace Nop.Plugin.Pricing.PreciousMetals.Controllers
{
    [AdminAuthorize]
    public class PreciousMetalsPricingController : BaseNopController
    {
        private readonly IPreciousMetalsDetailService _preciousMetalsDetailService;
        private readonly IPermissionService _permissionService;
        private readonly AdminAreaSettings _adminAreaSettings;
        private readonly IProductService _productService;
        private readonly IMeasureService _measureService;
        private readonly ICurrencyService _currencyService;
        private readonly CurrencySettings _currencySettings;
        private readonly ICategoryService _categoryService;
        private readonly IPriceCalculationService _priceCalculationService;

        private readonly string _configureViewName;
        private readonly string _bulkEditViewName;
        private readonly string _listViewName;

        public PreciousMetalsPricingController(
            IPreciousMetalsDetailService preciousMetalsDetailService,
            IProductService productService,
            IPermissionService permissionService,
            AdminAreaSettings adminAreaSettings,
            IMeasureService measureService,
            ICurrencyService currencyService,
            CurrencySettings currencySettings,
            IPriceCalculationService priceCalculationService,
            ICategoryService categoryService)
        {
            this._preciousMetalsDetailService = preciousMetalsDetailService;
            this._permissionService = permissionService;
            this._adminAreaSettings = adminAreaSettings;
            this._productService = productService;
            this._measureService = measureService;
            this._currencyService = currencyService;
            this._currencySettings = currencySettings;
            this._priceCalculationService = priceCalculationService;
            this._categoryService = categoryService;

            _configureViewName = "Nop.Plugin.Pricing.PreciousMetals.Views.PreciousMetalsPricing.Configure";
            _bulkEditViewName = "Nop.Plugin.Pricing.PreciousMetals.Views.PreciousMetalsPricing.BulkEdit";
            _listViewName = "Nop.Plugin.Pricing.PreciousMetals.Views.PreciousMetalsPricing.List";
        }

        protected override void Initialize(System.Web.Routing.RequestContext requestContext)
        {
            //little hack here
            //always set culture to 'en-US' (Telerik Grid has a bug related to editing decimal values in other cultures). Like currently it's done for admin area in Global.asax.cs
            var culture = new CultureInfo("en-US");
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = culture;

            base.Initialize(requestContext);
        }

        [HttpGet]
        public ActionResult Configure(int productVariantId)
        {
            var detail = this._preciousMetalsDetailService.Get(productVariantId);

            var availableWeights = this.Weights.Select(
                weight => new SelectListItem
                {
                    Text = weight.Name,
                    Value = weight.Id.ToString(CultureInfo.InvariantCulture),
                    Selected = ((detail == null || detail.WeightId == 0) && weight.SystemKeyword == "troyounce")
                               || (detail != null && detail.WeightId == weight.Id)
                });

            var defaultWeightId = int.Parse(availableWeights.Single(w => w.Selected).Value);

            var currency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).Name;

            // TODO: Use Automapper
            var model = new PreciousMetalsDetailModel
            {
                Enabled = detail != null,
                ProductVariantId = productVariantId,
                MetalType = detail == null ? 0 : detail.MetalType,
                QuoteType = detail == null ? 0 : detail.QuoteType,
                Weight = detail == null ? 0 : detail.Weight,
                WeightId = detail == null ? defaultWeightId : detail.WeightId,
                PercentMarkup = detail == null ? 0 : detail.PercentMarkup,
                FlatMarkup = detail == null ? 0 : detail.FlatMarkup,
                TierPriceType = detail == null ? 0 : detail.TierPriceType,
                LowerAmount = detail == null ? 0 : detail.LowerAmount,
                MathType = detail == null ? 0 : detail.MathType,
                PriceRounding = detail == null ? 0 : detail.PriceRounding,
                PriceRoundingType = detail == null ? 0 : detail.PriceRoundingType,
                BaseCurrencyIn = currency,
                AvailableWeights = availableWeights
            };

            return View(_configureViewName, model);
        }

        [HttpPost]
        public ActionResult Configure(PreciousMetalsDetailModel model)
        {
            if (!model.Enabled)
            {
                this._preciousMetalsDetailService.Clear(model.ProductVariantId);
            }
            else
            {
                var detail = this._preciousMetalsDetailService.Get(model.ProductVariantId) ?? new PreciousMetalsDetail();

                // TODO: Use Automapper
                detail.ProductVariantId = model.ProductVariantId;
                detail.MetalType = model.MetalType;
                detail.QuoteType = model.QuoteType;
                detail.Weight = model.Weight;
                detail.PercentMarkup = model.PercentMarkup;
                detail.FlatMarkup = model.FlatMarkup;
                detail.TierPriceType = model.TierPriceType;
                detail.MathType = model.MathType;
                detail.LowerAmount = model.LowerAmount;
                detail.WeightId = model.WeightId;
                detail.PriceRounding = model.PriceRounding;
                detail.PriceRoundingType = model.PriceRoundingType;

                this._preciousMetalsDetailService.Save(detail);
            }

            return new EmptyResult();
        }

        [HttpGet]
        public ActionResult BulkEdit()
        {
            var model = new PreciousMetalsGroupModel { AvailableWeights = new List<SelectListItem>() };

            foreach (var weight in Weights)
                model.AvailableWeights.Add(new SelectListItem { Text = weight.Name, Value = weight.Id.ToString(CultureInfo.InvariantCulture), Selected = (weight.Id == model.WeightId) });

            model.AvailableCategories = new List<SelectListItem>();
            foreach (var category in _categoryService.GetAllCategories())
                model.AvailableCategories.Add(new SelectListItem { Text = category.Name, Value = category.Id.ToString(CultureInfo.InvariantCulture) });

            model.BaseCurrencyIn = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).Name;

            return View(_bulkEditViewName, model);
        }

        [HttpPost]
        public ActionResult BulkEdit(PreciousMetalsGroupModel model)
        {
            if (model.CategoryId <= 0)
                return RedirectToAction("List");

            var details = this._categoryService.GetProductCategoriesByCategoryId(model.CategoryId)
                .SelectMany(category => category.Product.ProductVariants.Select(variant => this._preciousMetalsDetailService.Get(variant.Id)))
                .Where(x => x != null);

            foreach (var detail in details)
            {
                if (model.OverrideFlatMarkup)
                    detail.FlatMarkup = model.FlatMarkup;
                if (model.OverrideLowerAmount)
                    detail.LowerAmount = model.LowerAmount;
                if (model.OverrideMathType)
                    detail.MathType = model.MathType;
                if (model.OverrideMetalType)
                    detail.MetalType = model.MetalType;
                if (model.OverridePercentMarkup)
                    detail.PercentMarkup = model.PercentMarkup;
                if (model.OverrideQuoteType)
                    detail.QuoteType = model.QuoteType;
                if (model.OverrideTierPriceType)
                    detail.TierPriceType = model.TierPriceType;
                if (model.OverrideWeight)
                    detail.Weight = model.Weight;
                if (model.OverrideWeightUnit)
                    detail.WeightId = model.WeightId;
                if (model.OverridePriceRounding)
                    detail.PriceRounding = model.PriceRounding;
                if (model.OverridePriceRoundingType)
                    detail.PriceRoundingType = model.PriceRoundingType;

                this._preciousMetalsDetailService.Save(detail);
            }

            return RedirectToAction("List", "Plugins/PreciousMetals/Admin");
        }

        public ActionResult Index()
        {
            return RedirectToAction("List", "Plugins/PreciousMetals/Admin");
        }

        public ActionResult List()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
                return AccessDeniedView();

            var items = _preciousMetalsDetailService.GetAll(0, _adminAreaSettings.GridPageSize);

            var listModel = new GridModel<PreciousMetalsGridDetailModel>
            {
                Data = items.Select(this.PrepareModelForList),
                Total = items.TotalCount
            };

            ViewData["AvailableWeights"] = Weights;

            //WeightUnitsJS

            var builder = new StringBuilder();
            builder.AppendLine("var weightUnits = new Array();");
            builder.AppendLine("weightUnits[0] = \"---\"");
            foreach (var weight in Weights)
            {
                builder.AppendFormat("weightUnits[{0}] = \"{1}\"", weight.Id, Server.HtmlEncode(weight.Name));
                builder.AppendLine();
            }

            ViewData["WeightUnitsJS"] = builder.ToString();

            return View(_listViewName, listModel);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult PricingList(GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
                return AccessDeniedView();

            var items = _preciousMetalsDetailService.GetAll(command.Page - 1, command.PageSize);

            var gridModel = new GridModel<PreciousMetalsGridDetailModel>
            {
                Data = items.Select(this.PrepareModelForList),
                Total = items.TotalCount
            };

            return new JsonResult { Data = gridModel };
        }


        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult BulkEditSelect(GridCommand command)
        {
            return PricingList(command);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult BulkEditSave(GridCommand command,
            [Bind(Prefix = "updated")]IEnumerable<PreciousMetalsGridDetailModel> updatedPreciousMetalsDetailModel,
            [Bind(Prefix = "deleted")]IEnumerable<PreciousMetalsGridDetailModel> deletedPreciousMetalsDetailModel)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
                return AccessDeniedView();

            if (updatedPreciousMetalsDetailModel != null)
            {
                foreach (var model in updatedPreciousMetalsDetailModel)
                {
                    //update
                    var detail = _preciousMetalsDetailService.Get(model.ProductVariantId);
                    if (detail == null)
                        continue;

                    detail.FlatMarkup = model.FlatMarkup;
                    detail.MetalType = (int)model.MetalType;
                    detail.PercentMarkup = model.PercentMarkup;
                    detail.QuoteType = (int)model.QuoteType;
                    detail.TierPriceType = (int)model.TierPriceType;
                    detail.Weight = model.Weight;
                    detail.MathType = (int)model.MathType;
                    detail.LowerAmount = model.LowerAmount;
                    detail.WeightId = model.WeightId;
                    detail.PriceRounding = model.PriceRounding;
                    detail.PriceRoundingType = (int)model.PriceRoundingType;

                    this._preciousMetalsDetailService.Save(detail);
                }
            }

            if (deletedPreciousMetalsDetailModel != null)
            {
                foreach (var model in deletedPreciousMetalsDetailModel)
                {
                    //delete
                    var detail = _preciousMetalsDetailService.Get(model.ProductVariantId);
                    if (detail != null)
                        _preciousMetalsDetailService.Clear(model.ProductVariantId);
                }
            }

            return BulkEditSelect(command);
        }


        private IEnumerable<MeasureWeight> _weights;
        private IEnumerable<MeasureWeight> Weights
        {
            get { return this._weights ?? (this._weights = this._measureService.GetAllMeasureWeights()); }
        }

        private PreciousMetalsGridDetailModel PrepareModelForList(PreciousMetalsDetail detail)
        {
            var productVariantTitle = this._productService.GetProductVariantById(detail.ProductVariantId).FullProductName;

            var preciousMetalsPriceCalculationService = (PreciousMetalsPriceCalculationService)this._priceCalculationService;
            var currentPrice = preciousMetalsPriceCalculationService.GetMetalPiecePrice(detail);

            return new PreciousMetalsGridDetailModel
            {
                Enabled = true,
                ProductVariantId = detail.ProductVariantId,
                MetalType = (PreciousMetalType)detail.MetalType,
                QuoteType = (PreciousMetalsQuoteType)detail.QuoteType,
                Weight = detail.Weight,
                WeightId = detail.WeightId,
                PercentMarkup = detail.PercentMarkup,
                FlatMarkup = detail.FlatMarkup,
                TierPriceType = (PreciousMetalsTierPriceType)detail.TierPriceType,
                ProductVariantTitle = productVariantTitle,
                MathType = (PreciousPriceCalculationType)detail.MathType,
                CurrentPrice = currentPrice,
                LowerAmount = detail.LowerAmount,
                PriceRounding = detail.PriceRounding,
                PriceRoundingType = (PriceRoundingType)detail.PriceRoundingType
            };
        }
    }
}
